import sys;
sys.path.append('..');
from by.vaukalak.core.application.Application import *;
from by.vaukalak.core.net.socket.SocketServer import *;
from by.vaukalak.core.net.socket.SocketEvent import *;
from by.vaukalak.core.net.commands.CommandSerializer import *;
from core.BoardData import BoardData;
from core.PeacePosition import *;
from rules.RulesController import *;
from game.Player import Player;
from game.PlayerEvent import PlayerEvent;

class Game(EventDispatcher):

    def __init__(self, dataBase):
        EventDispatcher.__init__(self);
        self.player1 = None;
        self.player2 = None;
        self._dataBase = dataBase;
        self._serializer = CommandSerializer();
        self._boardData = BoardData();
        self._rulesController = RulesController(self._boardData);
        self._isGameComplete = False;

    def start(self):
        self._id = self._dataBase.createNewGame(self.player1, self.player2);
        print "game id:\t" + self._id;
        clients = [self.player1, self.player2];
        self.player1.rulesController = self.player2.rulesController = self._rulesController;
        for i in (0,1):
            response = self._serializer.serialize(Command("buildGame", [self._boardData.matrix, i]));
            clients[i].connection.send(response);
            clients[i].addEventListener(PlayerEvent.MOTION_REQUEST, self.heandleMotionRequest);
            clients[i].addEventListener(PlayerEvent.SELECT_PEACE, self.heandlePeaceChangeRequest);
            clients[i].addEventListener(PlayerEvent.DISCONNECTED, self._handlePlayerDisconnect);
        self.setCurrentPlayer(self.player1);
        self.broadCastMessage(Command("giveTurn", [self._currentPlayer.color]));

    def _handlePlayerDisconnect(self, event):
        print "player disconnected";
        winner = self._getOtherPlayer(event.target);
        self._conclusion = "DISCONNECT";
        self._winner = winner;
        #winner.send(Command("notifyUser", ["victory"]));
        self.endTheGame();


    def heandlePeaceChangeRequest(self, event):
        self.broadCastMessage(Command("changePeace", [self._promovePosition.serialize(), event.command.params[0]]));
        self._rulesController.boardData.changePeace(self._promovePosition, int(event.command.params[0]));


    def heandleMotionRequest(self, event):

        self._currentPlayer.alreadyOnTron = self._currentPlayer.hasNobelOnTron;
        command = event.command;

        sP = PeacePosition.fromHash(command.params[0]);
        fP = PeacePosition.fromHash(command.params[1]);

        if(event.target != self._currentPlayer):
            self.broadCastMessage(Command("processMotion", [sP.serialize(), sP.serialize()]));
            self.broadCastMessage(Command("giveTurn", [self._currentPlayer.color]));
            return;

        if(self._rulesController.processMotion(sP, fP)):
            self.broadCastMessage(Command("processMotion", [sP.serialize(), fP.serialize()]));
            if(self._opponentPlayer.hasKniaz):
                self.nextPlayer = self._opponentPlayer;
            else:
                if self._opponentPlayer.hasKniazhych:
                    changePeaceCell, kniazType = self._opponentPlayer.declareKniaz();
                    self.nextPlayer = self._currentPlayer;
                    self.broadCastMessage(Command("notifyUser", ["declareKniaz"]));
                    self.broadCastMessage(Command("changePeace", [changePeaceCell.serialize(), kniazType]));
                else:
                    self._conclusion = "CHECKMATE";
                    self._winner = self._currentPlayer;
                    self.endTheGame();
        else:
            self.nextPlayer = self._currentPlayer;
            self.broadCastMessage(Command("processMotion", [sP.serialize(), sP.serialize()]));

        self._promovePosition = self._currentPlayer.hasToPromovePawn;
        if self._promovePosition:
            if len(self._currentPlayer.missingPeaces):
                self._currentPlayer.send(Command("displayPeaceChiose", [self._currentPlayer.missingPeaces]));
            else:
                self.broadCastMessage(Command("changePeace", [self._promovePosition.serialize(), self._currentPlayer.vaukalakType]));
                self._rulesController.boardData.changePeace(self._promovePosition, self._currentPlayer.vaukalakType);
                self._processMotionOutcomes();
        else:
            self._processMotionOutcomes();

    def _processMotionOutcomes(self):
        if(not self.gameOver):
            if(self.nextPlayer != self._currentPlayer):
                if(self._currentPlayer.hasNobelOnTron):
                    self.broadCastMessage(Command("notifyUser", ["tron"]));
                if(self.nextPlayer.isUnderRokash):
                    self.broadCastMessage(Command("notifyUser", ["rokash"]));
                if(self.nextPlayer.isUnderCheck):
                    self.broadCastMessage(Command("notifyUser", ["shah"]));

            self.setCurrentPlayer(self.nextPlayer);
            self.broadCastMessage(Command("giveTurn", [self._currentPlayer.color]));
        else:
            self.endTheGame();


    @property
    def gameOver(self):
        if(self.nextPlayer == self._currentPlayer):
            return False;

        if(self._currentPlayer.hasNobelOnTron):
            if(self._currentPlayer.alreadyOnTron):
                self._conclusion = "TRON";
                self._winner = self._currentPlayer;
                return True;
            if(not self.nextPlayer.canPutOnRokash):
                self._conclusion = "TRON";
                self._winner = self._currentPlayer;
                return True;
        if(self.nextPlayer.isUnderCheck):
            if(not self.nextPlayer.canRunFromCheck):
                self._conclusion = "CHECKMATE";
                self._winner = self._currentPlayer;
                return True;

        return False;

    def endTheGame(self):
        if(not self._isGameComplete):
            self._dataBase.setWinner(self._id, self._winner, self._conclusion);
        self._isGameComplete = True;
        self.broadCastMessage(Command("notifyUser", ["victory"]));

    def setCurrentPlayer(self, player):
        self._currentPlayer = player;
        self._rulesController.currentPlayer = player;
        self._opponentPlayer = self._getOtherPlayer(player);
        self._rulesController.opponentPlayer = self._opponentPlayer;

    @property
    def id(self):
        return self._id;

    def broadCastMessage(self, command):
        clients = [self.player1, self.player2];
        for i in (0,1):
            if(clients[i].isConnected):
                clients[i].send(command);

    #PRIVATE METHODS

    def _getOtherPlayer(self, player):
        if(player == self.player1):
            return self.player2;
        else:
            return self.player1;
